home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tricks of the Mac Game Programming Gurus
/
TricksOfTheMacGameProgrammingGurus.iso
/
More Source
/
Pascal
/
OffscreenToys
/
OffscreenToys 1.3
/
OffscreenToysUtils.p
< prev
Wrap
Text File
|
1995-01-11
|
11KB
|
347 lines
{Minimalist's offscreen package - reuseable code from OffscreenToys.}
{This unit implements glue for using "cicn" resources and GWorlds. It works on all Macs I can}
{imagine, including Macs without 32-bit QD or Color QD.}
unit OffscreenToysUtils;
interface
uses
{$IFC UNDEFINED THINK_PASCAL}
Types, QuickDraw, Events, Windows, Dialogs, Fonts, DiskInit, TextEdit, Traps, Desk, Memory,{}
SegLoad, Scrap, ToolUtils, OSEvents, OSUtils, Menus, Resources, Packages, {}
{$ENDC}
QDOffScreen;
{Generate a random number in a limited range}
{function Rand (range: integer): integer;}
{Glue for GWorlds}
procedure OTGetGWorld (var thePort: GrafPtr; var theDevice: GDHandle);
procedure OTSetGWorld (thePort: GrafPtr; theDevice: GDHandle);
{Glue for cicns}
function OTGetCicn (cicnId: integer): CIconHandle;
procedure OTPlotCicn (theCicn: CIconHandle; destWorld: GrafPtr; r: Rect);
procedure OTDisposeCicn (theCicn: CIconHandle);
function OTGetBoostCicn (cicnId: integer): GrafPtr;
procedure OTPlotBoostCicn (theCicn, destPort: GrafPtr; where: Point);
{NewPtr with built-in error check}
function OTNewPtr (size: Longint): Ptr;
{Glue for making GWorlds}
procedure OTNewGWorld (var offscreenGWorld: GrafPtr; boundsRect: Rect);
procedure OTDisposeGWorld (var offscreenGWorld: GrafPtr);
{Apples code for TrapAvailable}
function TrapAvailable (theTrap: Integer): Boolean;
{Initialize the globals - must be done first!}
procedure OTInitGlobals;
var
gColorQDFlag: Boolean; {True if 32-bit QD exists. If not, we run everything in b/w.}
gHasWNE: Boolean; {True if we can use WaitNextEvent}
gSoundFlag: Boolean; {True if Sound Manager is around.}
implementation
{Taken out from:}
{ --- PART 2: Various general, reuseable routines, mostly glue: ---------------------}
{Rand: simply make a random number between 0 and range-1.}
function Rand (range: integer): integer;
begin
Rand := abs(Random mod range)
end;
{BailOut: Emergency exit. We go here on most errors. Real programs report what the}
{problem is. You may wish to put a breakpoint in BailOut when debugging.}
procedure BailOut;
begin
SysBeep(1); {Minimal error message. Use alert in real programs.}
halt;
end;
{OTGetGWorld and OTSetGWorld: Glue to GetGWorld and SetGWorld, so this will work}
{without 32-bit QD, if necessary.}
procedure OTGetGWorld (var thePort: GrafPtr; var theDevice: GDHandle);
begin
theDevice := nil;
if gColorQDFlag then
GetGWorld(CGrafPtr(thePort), theDevice)
else
GetPort(thePort);
end;
procedure OTSetGWorld (thePort: GrafPtr; theDevice: GDHandle);
begin
if gColorQDFlag then
SetGWorld(CGrafPtr(thePort), theDevice)
else
SetPort(thePort);
end;
{OTGetCicn: Glue to GetCIcon, loads a cicn resource}
function OTGetCicn (cicnId: integer): CIconHandle;
var
h: Handle;
begin
if gColorQDFlag then
begin
OTGetCicn := GetCIcon(cicnId);
h := GetResource('cicn', cicnID);
ReleaseResource(h);
end
else
OTGetCicn := CIconHandle(GetResource('cicn', cicnId));
end;
{OTPlotCicn: Glue to PlotCIcon, plots a cicn.}
procedure OTPlotCicn (theCicn: CIconHandle; destWorld: GrafPtr; r: Rect);
var
tempIconBMap, tempIconMask: BitMap;
savePort: GrafPtr;
saveDevice: GDHandle;
datasize: integer;
begin
OTGetGWorld(savePort, saveDevice);
if destWorld <> nil then
OTSetGWorld(destWorld, nil)
else
destWorld := savePort; {So that CopyMask has a GrafPtr!}
if theCicn <> nil then {If we have a cicn}
if gColorQDFlag then {We have color - then it's easy.}
PlotCicon(r, theCicn)
else
{No color: Use CopyMask.}
{NOTE: This only works for 9 pixels or wider cicn's! (Old QuickDraw can't handle 1 byte wide bitmaps.)}
{There is a workaround for this, but that is *really* tedious.}
begin
HLock(Handle(theCicn));
{Make the base address pointers valid}
with theCicn^^.iconBMap do
datasize := rowBytes * (bounds.bottom - bounds.top);
theCicn^^.iconBMap.baseAddr := Ptr(longint(@theCicn^^.iconMaskData[0]) + datasize); {Bitmappen måste vara giltig fört!}
theCicn^^.iconMask.baseAddr := @theCicn^^.iconMaskData[0]; {Maskbitmappen måste också vara giltig först!}
{Draw with CopyMask}
CopyMask(theCicn^^.iconBMap, theCicn^^.iconMask, destWorld^.portBits, theCicn^^.iconBMap.bounds, theCicn^^.iconBMap.bounds, r);
HUnLock(Handle(theCicn));
end;
OTSetGWorld(savePort, saveDevice);
end;
procedure OTDisposeCicn (theCicn: CIconHandle);
begin
if gColorQDFlag then
DisposeCIcon(theCicn)
else
ReleaseResource(Handle(theCicn));
end;
{To avoid a lot of boring checks later, we have a glue for NewPtr, making it emergency}
{exit on out of memory. (This is of course often not what you want, but this is a demo!)}
function OTNewPtr (size: Longint): Ptr;
begin
OTNewPtr := NewPtrClear(size);
if MemError <> noErr then
BailOut;
end;
{OTNewGWorld: Glue to NewGWorld}
{I declare offscreenGWorld as GrafPtr to save us a bunch of typecasts later (in CopyBits).}
{Most parameters to NewGWorld omitted - NewGWorld is smart enough to make the defaults useable.}
procedure OTNewGWorld (var offscreenGWorld: GrafPtr; boundsRect: Rect);
var
theDevice, oldDevice: GDHandle;
ourCMHandle: CTabHandle;
err: OsErr;
saveGD: GDHandle;
savePort: GrafPtr;
begin
OTGetGWorld(savePort, saveGD);
if gColorQDFlag then
begin
if noErr <> NewGWorld(GWorldPtr(offscreenGWorld), 0, boundsRect, nil, nil, [pixelsLocked]) then
BailOut;
{We lock the offscreen pixmap so we can CopyBits and PlotCIcon to it.}
if LockPixels(CGrafPtr(offscreenGWorld)^.portPixMap) then
;
{Note: We should unlock it (UnlockPixels) when not animating, to avoid memory fragmentation,}
{but you can bother with that later if it's a problem.}
end
else
begin
{Not color - setup in b/w}
offscreenGWorld := GrafPtr(OTnewPtr(sizeof(GrafPort)));
OpenPort(offscreenGWorld);
offscreenGWorld^.portRect := boundsRect;
offscreenGWorld^.portBits.bounds := offscreenGWorld^.portRect;
RectRgn(offscreenGWorld^.visRgn, boundsRect);
ClipRect(boundsRect);
offscreenGWorld^.portBits.rowBytes := longint(((offscreenGWorld^.portRect.right - offscreenGWorld^.portRect.left + 15) div 16) * 2);
offscreenGWorld^.portBits.baseAddr := OTnewPtr(offscreenGWorld^.portBits.rowBytes * longint(offscreenGWorld^.portRect.bottom - offscreenGWorld^.portRect.top));
end;
OTSetGWorld(savePort, saveGD);
end;
{OTDisposeGWorld: Glue to DisposeGWorld}
procedure OTDisposeGWorld (var offscreenGWorld: GrafPtr);
begin
if gColorQDFlag then
begin
DisposeGWorld(GWorldPtr(offscreenGWorld));
end
else
begin
DisposePtr(offscreenGWorld^.portBits.baseAddr);
DisposePtr(Ptr(offscreenGWorld));
end;
offscreenGWorld := nil;
end;
{TrapAvailable from IM6-3-8}
function NumToolboxTraps: Integer;
begin
if NGetTrapAddress($A86E, ToolTrap) = NGetTrapAddress($aa6e, ToolTrap) then {_InitGraf}
NumToolboxTraps := $200
else
NumToolboxTraps := $400;
end;
function GetTrapType (theTrap: Integer): TrapType;
const
TrapMask = $800;
begin
if band(theTrap, TrapMask) > 0 then
GetTrapType := ToolTrap
else
GetTrapType := OSTrap;
end;
function TrapAvailable (theTrap: Integer): Boolean;
var
tType: TrapType;
begin
tType := GetTrapType(theTrap);
if tType = ToolTrap then
begin
theTrap := band(theTrap, $7ff);
if theTrap >= NumToolboxTraps then
theTrap := $A89F;{_Unimplemented}
end;
TrapAvailable := NGetTrapAddress(theTrap, tType) <> NGetTrapAddress($A89F, ToolTrap);{_Unimplemented}
end;
{End of code from IM6}
procedure OTInitGlobals;
const
{Trap numbers}
_WaitNextEvent = $A860;
_GetCIcon = $AA1E; {E.g. any Color QuickDraw routine}
k32bQD = $AB1D;
_SndPlay = $A805;
begin
gHasWNE := TrapAvailable(_WaitNextEvent);
gColorQDFlag := TrapAvailable(k32bQD) and TrapAvailable(_GetCIcon); {???}
gSoundFlag := TrapAvailable(_SndPlay);
{$IFC UNDEFINED THINK_PASCAL}
qd.randSeed := TickCount; {Seed the random number generator - TickCount is good enough.}
{$ELSEC}
randSeed := TickCount; {Seed the random number generator - TickCount is good enough.}
{$ENDC}
end;
{Load a cicn to a GWorld. Wastes some memory, but if it isn't too many, the speed increase pays}
{for it.}
function OTGetBoostCicn (cicnId: integer): GrafPtr;
var
offscreenGWorld: GrafPtr;
theCicn: CIconHandle;
saveGD: GDHandle;
savePort: GrafPtr;
begin
OTGetGWorld(savePort, saveGD);
theCicn := OTGetCicn(cicnId);
OTNewGWorld(offscreenGWorld, theCicn^^.iconMask.bounds);
if offscreenGWorld <> nil then
begin {OTSetGWorld(offscreenGWorld, nil); Onödigt!}
OTPlotCicn(theCicn, offscreenGWorld, theCicn^^.iconMask.bounds);
{I use the clipRgn for storing the mask region. This may seem weird, but when we aren't drawing}
{in the GWorld anyway, it won't matter.}
if offscreenGWorld = nil then
offscreenGWorld^.clipRgn := NewRgn;
if gColorQDFlag and TrapAvailable($A8D7) then {a8d7 = BitMapToRegion}
begin
if noErr <> BitMapToRegion(offscreenGWorld^.clipRgn, theCicn^^.iconMask) then{}
offscreenGWorld^.clipRgn := nil;{or DisposeRgn?}
end
else {Trap not available - use the glue routine instead.}
begin
if noErr <> BitMapToRegionGlue(offscreenGWorld^.clipRgn, theCicn^^.iconMask) then{}
offscreenGWorld^.clipRgn := nil;{or DisposeRgn?}
end;
OTDisposeCicn(theCicn);
end;
OTSetGWorld(savePort, saveGD);
OTGetBoostCicn := offscreenGWorld;
end;
var
gTmpRgn: RgnHandle;
procedure OTPlotBoostCicn (theCicn, destPort: GrafPtr; where: Point);
var
saveGD: GDHandle;
savePort: GrafPtr;
bounds: Rect;
tmpRgn: RgnHandle;
saveForeColor, saveBackColor: RGBColor;
begin
OTGetGWorld(savePort, saveGD);
{OTSetGWorld(theCicn, nil);}
bounds := theCicn^.portRect;
OffsetRect(bounds, where.h - bounds.left, where.v - bounds.top);
if gTmpRgn = nil then
gTmpRgn := NewRgn; {For top speed, we make this global, and create it only once!}
CopyRgn(theCicn^.clipRgn, gTmpRgn);
OffsetRgn(gTmpRgn, where.h, where.v);
SetPort(destPort); {Device?}
if gColorQDFlag then
begin
GetForeColor(saveForeColor);
GetBackColor(saveBackColor);
end;
ForeColor(blackColor);
BackColor(whiteColor);
CopyBits(theCicn^.portBits, destPort^.portBits, theCicn^.portRect, bounds, srcCopy, gTmpRgn);
{DisposeRgn(tmpRgn);}
if gColorQDFlag then
begin
RGBForeColor(saveForeColor);
RGBBackColor(saveBackColor);
end;
OTSetGWorld(savePort, saveGD);
end;
end.